home *** CD-ROM | disk | FTP | other *** search
/ United Public Domain Gold 2 / United Public Domain Gold 2.iso / education / pe022.dms / pe022.adf / GRAVSIM / GRAVSIM.C < prev    next >
C/C++ Source or Header  |  1991-07-12  |  41KB  |  1,379 lines

  1. /*  
  2.  
  3.                  T H E        G R A V I T Y      S I M U L A T O R 
  4.                  -------------------------------------------------
  5.  
  6.    HISTORY:
  7.    =======
  8.  
  9.      Here is a neat little project that started out as a ONE screen long 
  10.    C program to simulate gravitational attraction amongst planets. A friend
  11.    and I thought of the idea for the program one day and we decided to write it.
  12.    
  13.    Originally, you had to recompile the ENTIRE program to change the parameters
  14.    that govern , gravity, velocity, mass etc.!!!
  15.  
  16.    Then I decided to allow it to read the parameters from an input file ! (WOW!)
  17.  
  18.    Until many months later ...  
  19.  
  20.       I decided to use the idea in my Computer Graphics Animation project at
  21.    Adelaide Uni. What came next was 2 weeks of solid hacking to produce a program 
  22.    that was MUCH EASIER to interact with !
  23.  
  24.       This is my first really USEFUL program I have written, I hope you like it !.
  25.  
  26.  
  27.       By the way I have gone to GREAT PAINS to make this C program as READABLE
  28.    as possible to help all those new C hackers out there! 
  29.  
  30.       I just wish there were more programs as readable as this when I go my
  31.    Amiga 1000 2 years ago!. 
  32.      
  33.  
  34.    THANKS:
  35.    =======
  36.     
  37.       Special thanks must go to my friend ROBERT WOZNIAK, who designed the
  38.     ORIGINAL formulae ( of which I have improved slightly ) that govern the 
  39.     planetary motion and to Michael Portmann, who supplied the idea of how to 
  40.     enter the mass of the planets via mouse.
  41.  
  42.  
  43.  
  44.     Title:        THE GRAVITY SIMULATOR.  Vr 1.50
  45.  
  46.  
  47.     Program by:   Richard Frost (C) 1988,1989. 
  48.                   Adelaide, South Australia, Australia.
  49.                   (The Grand Prix State!).
  50.  
  51.                   All code & I/O correct on:  10th August 1988
  52.                   Final Menu Interface Correct on: 6th August 1988 
  53.                   
  54.                   Additions: Loading & saving files & new project menu,
  55.                              November 24th 1988.
  56.  
  57.                              Status Bar on Screen Title during RECORD mode,
  58.                              May 20th 1989.
  59.  
  60.                              Coloured Paths implemented succesfully on
  61.                              May 21st, 3.30 AM. 
  62.                              (Yes AM! thats when REAL programmers work!!! )
  63.                                 
  64.                                 
  65.                   Bug Fixes: Loading & saving files fixed on 29th Jan 1989.
  66.  
  67. */
  68. #include <stdio.h>      
  69. #include <exec/types.h>
  70. #include <exec/tasks.h>
  71. #include <exec/libraries.h>
  72. #include <exec/devices.h>
  73. #include <devices/keymap.h>
  74. #include <graphics/copper.h>
  75. #include <graphics/display.h>
  76. #include <graphics/gfxbase.h>
  77. #include <graphics/text.h>
  78. #include <graphics/view.h>
  79. #include <graphics/gels.h>
  80. #include <graphics/regions.h>
  81. #include <hardware/blit.h>
  82. #include <intuition/intuition.h>
  83. #include <intuition/intuitionbase.h>
  84.  
  85.  
  86. #define XMAX 639
  87. #define XMIN 0
  88. #define YMAX 512
  89. #define YMIN 11
  90.  
  91. #define spriteXMAX 649
  92. #define spriteXMIN -15
  93. #define spriteYMAX 530
  94. #define spriteYMIN -10
  95.  
  96. #define SCALE_FACTOR 128
  97.  
  98. #define SCREEN_WIDTH XMAX+1         
  99.  
  100. #define SCREEN_HEIGHT YMAX+1      
  101. #define SCREEN_BITPLANES  2      /* have 4 colours  */
  102.                 
  103. #define StrGad  0       /* Gadget Label used in the requester */
  104.  
  105. #define PROJECT_MENU 0             /* Labels used for menu item events */ 
  106. #define   NEW_ITEM 0           
  107. #define   LOAD_ITEM 1 
  108. #define   SAVE_ITEM 2
  109. #define   QUIT_ITEM  3
  110.  
  111. #define PLANETS_MENU 1
  112. #define   PLACEPLANET_ITEM 0
  113. #define   REMOVEPLANET_ITEM 1
  114. #define   SETVELOCITY_ITEM 2
  115. #define   SETMASS_ITEM 3
  116. #define   PATHS_ITEM 4
  117.  
  118.  
  119. #define ANIMATION_MENU 2
  120. #define   STARTANIM_ITEM 0
  121. #define   STOPANIM_ITEM 1
  122. #define   RESTARTANIM_ITEM 2
  123.  
  124. #define RECORDER_MENU 3
  125. #define    RECORDER_ON_ITEM 0
  126. #define    RECORDER_OFF_ITEM 1
  127. #define    PLAYBACK_ITEM 2
  128. #define    PLAYBACKSPEED_ITEM 3 
  129. #define               FAST_ITEM 0 
  130. #define               MEDIUM_ITEM 1 
  131. #define               SLOW_ITEM 2 
  132.             
  133.  
  134.  
  135.  
  136.                     /* Flags to indicate coordinates types  */
  137.  
  138.  
  139.  
  140. #define NewCoord 0    /* Indicates the mouse coordinate x,y is
  141.                          to be used in rubber banding */
  142.                          
  143.  
  144. #define StartCoord 1  /* The start coordinate for the
  145.                          velocity vector */
  146.  
  147.                      
  148. #define EndCoord 2    /* The end coordinate for the velocity vector.*/
  149.  
  150.  
  151. extern struct Screen *OpenScreen();
  152. extern struct Library  *OpenLibrary();
  153. extern struct Window *OpenWindow();
  154. extern struct Message *GetMsg();
  155.  
  156. struct Library *IntuitionBase;
  157. struct Library *GfxBase;
  158. struct Window  *NoBorder;
  159. struct Screen *MyScreen;
  160. struct IntuiMessage *message;
  161.  
  162. #define  MAXplanets 6;   /* MAXimum number of planets on the screen */
  163.                         
  164.                           /* Various action flags */
  165.  
  166. BOOL PLACEPLANET = FALSE;
  167. BOOL REMOVEPLANET = FALSE;
  168. BOOL SETVELOCITY = FALSE;
  169. BOOL SETMASS = FALSE;
  170. BOOL RECORD = FALSE;
  171. BOOL COMPUTEANIM = FALSE;
  172. BOOL PLANETPATH = TRUE;
  173. BOOL COLOURPATHS = TRUE;
  174.  
  175.  
  176. char Default_Title[] = " THE GRAVITY SIMULATOR V1.50             By Richard Frost. © 1988, 1989",
  177.      Stats_Title[80];
  178.      
  179.      
  180.  
  181. SHORT PenColour =1;
  182. int PlanetNum = 0;  /* Number of planets currently on the screen */  
  183.                     /* ranges from 1..6 */
  184.  
  185.  
  186. /* include all the menu defns. */
  187.  
  188. #include "GravSim.h"
  189.  
  190.  
  191. /* sprite.h include. I could not be bothered */
  192. /* making a new pre-include file just for this! */
  193.  
  194. #ifndef GRAPHICS_SPRITE_H
  195. #define GRAPHICS_SPRITE_H
  196. struct SimpleSprite
  197. {
  198.     UWORD *posctldata;
  199.     UWORD height;
  200.     UWORD   x,y;    /* current position */
  201.     UWORD   num;
  202. };
  203. #endif
  204.  
  205.  
  206.  
  207. /* ======================== Planet Sprite Definition ======================== */
  208.  
  209. UWORD PlanetData1[12] = {
  210.         0x0000,0x0000,
  211.         0x2000,0x3000,
  212.         0x4800,0x7000,
  213.         0x5800,0x6000,
  214.         0x1000,0x2000,
  215.         0x0000,0x0000             
  216. };
  217.  
  218. UWORD PlanetData2[12] = {
  219.         0x0000,0x0000,
  220.         0x2000,0x3000,
  221.         0x4800,0x7000,
  222.         0x5800,0x6000,
  223.         0x1000,0x2000,
  224.         0x0000,0x0000             
  225. };
  226. UWORD PlanetData3[12] = {
  227.         0x0000,0x0000,
  228.         0x2000,0x3000,
  229.         0x4800,0x7000,
  230.         0x5800,0x6000,
  231.         0x1000,0x2000,
  232.         0x0000,0x0000             
  233. };
  234. UWORD PlanetData4[12] = {
  235.         0x0000,0x0000,
  236.         0x2000,0x3000,
  237.         0x4800,0x7000,
  238.         0x5800,0x6000,
  239.         0x1000,0x2000,
  240.         0x0000,0x0000             
  241. };
  242. UWORD PlanetData5[12] = {
  243.         0x0000,0x0000,
  244.         0x2000,0x3000,
  245.         0x4800,0x7000,
  246.         0x5800,0x6000,
  247.         0x1000,0x2000,
  248.         0x0000,0x0000             
  249. };
  250. UWORD PlanetData6[12] = {
  251.         0x0000,0x0000,
  252.         0x2000,0x3000,
  253.         0x4800,0x7000,
  254.         0x5800,0x6000,
  255.         0x1000,0x2000,
  256.         0x0000,0x0000             
  257. };
  258.  
  259. struct SimpleSprite PlanetSprite[7];   /* Array of sprite definitions */
  260.  
  261.                    /* number of sprite moves stored: */
  262.  
  263. #define FILMLENGTH 6999 
  264.                           /* arrays for movie */
  265.  
  266. SHORT MoviePlanet[FILMLENGTH],   /* the number of the planet for this data */
  267.       MovieScreenX[FILMLENGTH],  /* screen coordinates for this planet sprite */
  268.       MovieScreenY[FILMLENGTH];
  269.  
  270. int frame = 0;  /* the current frame position of the movie */
  271. int DelayFactor = 0;
  272.  
  273. float X[7],     /* X coordinate of the planet in world coordinates */
  274.       Y[7],     /* Y coordinate of the planet in world coordinates */
  275.       Mass[7],     /* The MASS of the planet */
  276.       Vx[7],    /* The X velocity */
  277.       Vy[7],    /* The Y velocity */
  278.  
  279.       tempX[7],     /* temporary variables used in the restart action */
  280.       tempY[7],    
  281.       tempMass[7],    
  282.       tempVx[7],    
  283.       tempVy[7];   
  284.  
  285. double sqrt();
  286.  
  287.               /* Macro to Display the status bar on the screen title */
  288.  
  289. #define DisplayStats(c)  sprintf(Stats_Title,"RECORDING SIMULATION...  Maximum Frame: %-4d   Current Frame: %-4d",FILMLENGTH+1,c);\
  290.                          SetWindowTitles(NoBorder,-1,Stats_Title);
  291.                                 
  292. #define RestoreTitle() SetWindowTitles(NoBorder,-1,Default_Title)
  293.  
  294. /* ======================================================================== */
  295. VOID CloseUpShop()      /* Close down Screens, windows & menus.. */
  296. {
  297.   int i;
  298.  
  299.    /* free up the sprites .. */
  300.  
  301.    for (i = 1 ; i <= 6 ; i++)
  302.      FreeSprite(i);
  303.  
  304.    ClearMenuStrip(NoBorder);
  305.    CloseWindow(NoBorder);
  306.    CloseScreen(MyScreen);
  307. }
  308. /* ======================================================================== */
  309. VOID OpenAll()
  310. {
  311.   IntuitionBase = (struct Library *) OpenLibrary("intuition.library",0L);
  312.   if (IntuitionBase == NULL)
  313.     exit(FALSE);
  314.         
  315.   GfxBase =  (struct Library *) OpenLibrary("graphics.library",0L);
  316.   if (GfxBase == NULL)
  317.     exit(FALSE);
  318. }
  319. /* ======================================================================== */
  320. VOID ClrScreen()
  321. {
  322.  struct RastPort *r;
  323.  
  324.  r= NoBorder->RPort;
  325.  SetAPen(r,0);
  326.  RectFill(r,0,0,XMAX,YMAX);
  327.  SetAPen(r,PenColour);
  328. }
  329. /* ======================================================================== */
  330. VOID  SetUpFrontEnd()    /*  Set up:  Screen,Menus,Gadgets Requesters etc.  */
  331. {
  332.  UWORD i,
  333.      red,green,blue,
  334.      colour_reg;
  335.  UWORD *PlanetData_ptr;
  336.  USHORT SpriteNum;
  337.  SHORT s_id;
  338.  int delay;
  339.  
  340. struct ViewPort *Vp;
  341.  
  342.  /* POWER WINDOWS doesn't know anything about PAL so I have to REMIND IT ..*/
  343.  
  344.  /* Uncomment the following line IF Power Windows has a 640*200 screen */
  345.  
  346.  /* NewScreenStructure.ViewModes = NewScreenStructure.ViewModes + LACE; */
  347.  
  348.  NewScreenStructure.Width = NewWindowStructure1.Width = SCREEN_WIDTH;
  349.  NewScreenStructure.Height = NewWindowStructure1.Height = SCREEN_HEIGHT;
  350.  
  351.  
  352.  MyScreen = OpenScreen(&NewScreenStructure); /* Try to create the screen */
  353.  
  354.  if (MyScreen != NULL) 
  355.    {
  356.      NewWindowStructure1.Screen = MyScreen;     /* assign screen pointer to the window */
  357.      NoBorder =OpenWindow(&NewWindowStructure1);
  358.      SetMenuStrip(NoBorder,&Menu1);     /*   Open up the Menus !   */
  359.      LoadRGB4(&MyScreen->ViewPort,Palette,4);
  360.  
  361.      /* Set up the colour palette for the sprites */
  362.  
  363.      for (colour_reg = 16 ; colour_reg < 32 ; colour_reg += 4 )
  364.        {
  365.          SetRGB4(&MyScreen->ViewPort,colour_reg,0,0,0);
  366.          SetRGB4(&MyScreen->ViewPort,colour_reg+1,8,6,4);
  367.          SetRGB4(&MyScreen->ViewPort,colour_reg+2,10,7,5);
  368.          SetRGB4(&MyScreen->ViewPort,colour_reg+3,13,9,6);
  369.        }
  370.  
  371.      Vp = &MyScreen->ViewPort;
  372.         
  373.  
  374.     /* See if we can allocate the 6 sprites first ... */
  375.  
  376.     for (SpriteNum = 1; SpriteNum <= 6 ; SpriteNum++)
  377.        {
  378.  
  379.          /* Set the mass of that planet #spritenum = 0 */
  380.  
  381.         Mass[SpriteNum] = 0;
  382.  
  383.         if ( (s_id = GetSprite(&(PlanetSprite[SpriteNum]),SpriteNum))  !=  -1  )
  384.           {
  385.  
  386.            /* if we can allocate the sprite... */
  387.            /* Initialize the planet sprite (x,y) pos ... */
  388.                 
  389.            X[SpriteNum] = s_id * 70 * SCALE_FACTOR;
  390.            Y[SpriteNum] = 600 * SCALE_FACTOR;
  391.            Mass[SpriteNum] = 0;
  392.            PlanetSprite[SpriteNum].x =  s_id * 70 ;
  393.            PlanetSprite[SpriteNum].y = 600;
  394.            PlanetSprite[SpriteNum].height = 4;
  395.  
  396.            /* For some strange reason the Amiga doesn't like having 
  397.               multiple sprites sharing the same image structure !!!!
  398.  
  399.               WHY is this !!!!!!!!!!!!!!!!!!!!?????
  400.  
  401.               Thus I have declared each structure separately and the switch
  402.               below will ensure the pointer is pointing to the correct
  403.               one for sprite # SpriteNum */
  404.  
  405.            switch(SpriteNum)
  406.             {
  407.               case 1: PlanetData_ptr = PlanetData1;
  408.                       break;
  409.               case 2: PlanetData_ptr = PlanetData2;
  410.                       break;
  411.               case 3: PlanetData_ptr = PlanetData3;
  412.                       break;
  413.               case 4: PlanetData_ptr = PlanetData4;
  414.                       break;
  415.               case 5: PlanetData_ptr = PlanetData5;
  416.                       break;
  417.               case 6: PlanetData_ptr = PlanetData6;
  418.                       break;
  419.  
  420.             }
  421.  
  422.            /* Display the sprite out of the viewing area */
  423.            /* so that when a user MAKES a planet, only a sprite */
  424.            /* repositioning is required. */
  425.  
  426.            ChangeSprite(Vp,&(PlanetSprite[SpriteNum]),PlanetData_ptr);
  427.  
  428.           }
  429.         else
  430.           printf("CANNOT ALLOCATE SPRITE #%ld\n",(LONG)(SpriteNum) );
  431.  
  432.        } /* end for loop */
  433.  
  434.    }
  435.  else
  436.    {
  437.      printf("CANT OPEN HIRES SCREEN!!!\n");
  438.      exit(FALSE);
  439.    }
  440. }
  441.  
  442.  
  443. /* ======================================================================== */
  444. SHORT absolute(val)
  445. SHORT val;
  446.   if (val <0) 
  447.     return(-val);
  448.   else
  449.     return(val);
  450. }    
  451. /* ======================================================================== */
  452.  
  453. VOID SetVelocityVector(pnum,x,y,stateflag)
  454. LONG pnum,x,y,stateflag;
  455. {
  456.    /* These variables are not destroyed on block exit
  457.       and are used to keep track of what state the program is in */
  458.  
  459.   static LONG Xstart,Ystart,   
  460.               Xold,Yold,planetnumber;
  461.  
  462.   switch (stateflag)
  463.    {
  464.                       
  465.      case NewCoord:   if ((Xold != x) || (Yold != y))
  466.                         {
  467.                           /* erase OLD line using COMPLEMENT mode*/
  468.  
  469.                           Move(NoBorder->RPort,Xstart,Ystart);
  470.                           Draw(NoBorder->RPort,Xold,Yold);
  471.                            
  472.                           /* Draw the new line */
  473.  
  474.                           Move(NoBorder->RPort,Xstart,Ystart);
  475.                           Draw(NoBorder->RPort,x,y);  
  476.  
  477.                           /* Remember where these coordinates are 
  478.                              so we can erase this line when the Mouse moves */
  479.  
  480.                           Xold = x; 
  481.                           Yold = y; 
  482.                         } break;    
  483.  
  484.      case StartCoord: /* Store the start point and old points */ 
  485.  
  486.                       planetnumber = pnum;
  487.  
  488.                       Xstart = x; 
  489.                       Ystart = y;
  490.                       Xold = x + (long)Vx[planetnumber];
  491.                       Yold = y + (long)Vy[planetnumber];
  492.  
  493.                       Move(NoBorder->RPort,Xstart,Ystart);
  494.                       Draw(NoBorder->RPort,Xold,Yold);
  495.  
  496.                       break;
  497.  
  498.      case EndCoord:   /* The user released the LEFT mouse button 
  499.  
  500.                          1) Draw the final vector,
  501.                               vector LENGTH proportional to magnitude.
  502.                               x & y displacements should be scaled 
  503.                               appropriately to produce Vx,Vy.
  504.  
  505.                          2) Update the velocity components
  506.                             of the appropriate mass.
  507.  
  508.                          NOTE: This will leave the vectors still
  509.                                on the screen. 
  510.  
  511.                                Thus when the user selects START ANIMATION
  512.                                in the menu, the screen is cleared.
  513.                        */
  514.  
  515.                         /* delete the old vector */
  516.                         Move(NoBorder->RPort,Xstart,Ystart);
  517.                         Draw(NoBorder->RPort,Xold,Yold);
  518.  
  519.                         /* draw the vector selected by the user */
  520.  
  521.                         SetDrMd(NoBorder->RPort,JAM1);
  522.                         SetAPen(NoBorder->RPort,1);
  523.                         Move(NoBorder->RPort,Xstart,Ystart);
  524.                         Draw(NoBorder->RPort,x,y); 
  525.  
  526.                         /* alter the velocity of that planet! */
  527.                         Vx[planetnumber] = x - Xstart ;
  528.                         Vy[planetnumber] = y - Ystart ;
  529.  
  530.                       break; 
  531.    }
  532. }      
  533. /* ======================================================================= */
  534. VOID GravityAttract(M1,M2,deltaX,deltaY,vx,vy)
  535. float M1,M2,deltaX,deltaY,*vx,*vy;
  536. {
  537. static float TimeStep;   /* This is the delta Time step */
  538. float F,
  539.       Fx,Fy,
  540.       r,ax,ay;
  541.  
  542. #define G 5000.0 
  543.  
  544.  
  545.       /* First compute the separation distance R between the */
  546.       /* 2 masses M1 and M2, where: 
  547.  
  548.          deltaX =  the X displacement between masses M1 & M2.
  549.          deltaY =  the Y displacement between masses M1 & M2. */
  550.  
  551. #ifdef DEBUG
  552.       printf("\nIn Gravity attract.\n");
  553.       printf("delx,dely = %f,%f\n",deltaX,deltaY);
  554.       printf("M1,M2 = %f,%f\n",M1,M2);
  555.       printf("Vx,Vy = %f %f \n",*vx,*vy);
  556. #endif
  557.          
  558.       r =  sqrt( (double) (deltaX*deltaX + deltaY*deltaY) ) ; 
  559.  
  560.       if (r < 2000 ) 
  561.          {
  562.            TimeStep = r * 0.04 + 1; 
  563.          }
  564.        else
  565.            TimeStep = 80.0;
  566.  
  567.       /* Next, compute the mutual force of attraction, F, between the */
  568.       /* 2 masses using the standard GRAVITY FORMULA */
  569.  
  570.       F =  G * M1 * M2/(r*r);
  571.  
  572.       /* Now as the force vector between the 2 masses is parallel to the */
  573.       /* displacement vector between them, we can use proportions */
  574.       /* and similar triangles to evaluate the the magnitude of the */
  575.       /* X and Y components of F relative to the displacements deltaX */
  576.       /* and deltaY. */
  577.  
  578.       Fx = F * deltaX/r;
  579.       Fy = F * deltaY/r;
  580.  
  581.       /* The resultant acceleration of MASS 1 can be found by using */
  582.       /* Newton's First Law  F = M * A .  */
  583.       /* 'TimeStep' appears in this equation as it is used in the */
  584.       /* evaluation of velocity later on.*/
  585.  
  586.       ax = TimeStep * Fx/M1;    
  587.       ay = TimeStep * Fy/M1;
  588.  
  589.       /* Use the equation: V2 = V1 + ACCELERATION * TIME   */
  590.  
  591.       /* NOTE: This equation is only valid for CONSTANT acceleration */
  592.       /*       however accln. is not constant in real life gravity problems. */
  593.       /*       In my program I use a relatively small delta Time */
  594.       /*       increments, sufficiently small enough such that my program */
  595.       /*       effectively integrates the changes in acceleration over time. */
  596.    
  597.       /*       The major problem with this theory is that when 2 planets */
  598.       /*       are very close to each other the mutual force increases by */
  599.       /*       an inverse square law and my program steps through time */
  600.       /*       too quickly at this stage and the result is that when the */
  601.       /*       masses pass each other they still have a large velocity */
  602.       /*       as there was not enough time intervals in which either */
  603.       /*       planet's velocity is reduced by force due to the the other.*/
  604.     
  605.       *vx += ax;
  606.       *vy += ay;
  607.  
  608. #ifdef DEBUG
  609.       printf("out of Gravity attract.\n");
  610. #endif
  611.  
  612. }
  613. /* ======================================================================== */
  614. VOID MovePlanets()
  615.  float x1,y1,
  616.        vx1,vy1,
  617.        xop,yop;
  618.                                         
  619.  int xpos,ypos ;              
  620.  WORD p,otherp;
  621.  USHORT class;
  622.  SHORT sx,sy;
  623.  ULONG code;
  624.  
  625. /* Store the initial values before we start ! */
  626.  
  627.   for (p=1 ; p<=6 ; p++ )
  628.     {
  629.      tempX[p] = X[p];  
  630.      tempY[p] = Y[p];   
  631.      tempMass[p] = Mass[p];    
  632.      tempVx[p] = Vx[p];   
  633.      tempVy[p] = Vy[p]; 
  634.     }  
  635.  
  636.  if (RECORD)
  637.    {
  638.      DisplayStats(frame);
  639.    }
  640.  
  641. while (COMPUTEANIM)
  642.   {
  643.    for( p=1 ;p <= 6 ;p++)
  644.     {
  645.        /* for all planets 1...6 */
  646.  
  647.       if (Mass[p] != 0)    /* if the planet is on the screen then */
  648.         {
  649.            /* Find the overall force on planet 'p' */
  650.            /* due to all other planets 'otherp' on the screen */
  651.            /* ie. all those with non-zero mass */
  652.  
  653.            for( otherp=1 ;otherp<= 6 ; otherp++)
  654.             {
  655.               if ((otherp != p) && (Mass[otherp] != 0))
  656.                 { 
  657.                  /* obtain the new Vx and Vy velocities ... */
  658.  
  659.                  GravityAttract(Mass[p],
  660.                                 Mass[otherp],
  661.                                 X[otherp]-X[p],Y[otherp]-Y[p],
  662.                                 &Vx[p],&Vy[p]);
  663.                 }
  664.             }
  665.  
  666.             /* Excuse the following code, it is a remnant from the days
  667.                when I used Aztec 3.4a, which got very upset with arrays
  668.                used in complex expressions. */
  669.  
  670.            X[p] += Vx[p];
  671.            Y[p] += Vy[p];
  672.  
  673.            xpos = X[p] / SCALE_FACTOR ;           /* 128 = SCALE_FACTOR */
  674.            ypos = Y[p] / SCALE_FACTOR ; 
  675.  
  676.             /* if the planet 'p' is not out of the screen range then move it */
  677.  
  678.            if ((xpos > spriteXMIN && xpos < spriteXMAX)  && (ypos > spriteYMIN && ypos < spriteYMAX))
  679.             {
  680.               sx = (SHORT)xpos;
  681.               sy = (SHORT)ypos;
  682.               /* If in record mode and not out of 
  683.                  film then record the position! */
  684.  
  685.               if ( (RECORD) &&  frame < FILMLENGTH )
  686.                 {
  687.                   MovieScreenX[frame] = sx;
  688.                   MovieScreenY[frame] = sy;
  689.                   MoviePlanet[frame] = p;
  690.                   frame++;    /* Advance recorder to the next frame */
  691.                 }
  692.  
  693.               MoveSprite(&MyScreen->ViewPort,&PlanetSprite[p],sx,sy);
  694.  
  695.               if (PLANETPATH)
  696.                 {
  697.                  if ((xpos > XMIN  && xpos < XMAX) &&  (ypos > YMIN && ypos < YMAX))
  698.                      /* Toggle the paths */
  699.                    {
  700.                      if (COLOURPATHS)
  701.                         SetAPen(NoBorder->RPort,((p % 4) ? p : 1));
  702.                          
  703.                      WritePixel(NoBorder->RPort,sx+6 ,sy+3);
  704.                    }
  705.                 }
  706.             }
  707.  
  708.         } /* end if */
  709.  
  710.     } /* end for loop */
  711.  
  712.     if ( RECORD  && (frame % 100 == 0) )  /* WARNING: leave the following { } in!! */
  713.                                           /* Display Stats is a MACRO!!! */
  714.         {
  715.           DisplayStats(frame);
  716.         }
  717.  
  718.    /* See if the user hit the STOP button!!! */
  719.  
  720.     while ( message=(struct IntuiMessage *) GetMsg(NoBorder->UserPort) )
  721.       {
  722.        
  723.         /* If a message was recieved .... */
  724.     
  725.        class = message->Class;       /* Store the message class! */
  726.        code = message->Code;         /* Store the code */
  727.        ReplyMsg(message);         
  728.        
  729.        if ( (class ==  MENUPICK) && (MENUNUM(code) != MENUNULL) )
  730.          { 
  731.            if ((MENUNUM(code) == ANIMATION_MENU) && (ITEMNUM(code) == STOPANIM_ITEM))
  732.              {  
  733.                COMPUTEANIM = FALSE;
  734.                break;
  735.              }
  736.          }
  737.      } /* end event while loop */
  738.  
  739.  } /* End While loop */
  740.  
  741.  if (RECORD) 
  742.   {
  743.     DisplayStats(frame);
  744.   }
  745. }
  746.  
  747. /* ======================================================================== */
  748. VOID MakePlanet(xpos,ypos)
  749. SHORT xpos,ypos;
  750. {
  751.    USHORT scanplanet,
  752.           freeplanet;
  753.  
  754.     PlanetNum++;  
  755.  
  756.    /* find a planet that is free to use ! */
  757.  
  758.    for(scanplanet = 1 ; scanplanet <= 6 ; scanplanet++)
  759.      {
  760.        if (Mass[scanplanet] == 0)   /* FOUND AN UNUSED PLANET! */
  761.          {
  762.            freeplanet = scanplanet;
  763.            break;   /* exit the loop as we have found it! */
  764.          }
  765.      }          
  766.  
  767.  
  768.    /* Display the sprite by moving that sprite into the viewing area  */
  769.    MoveSprite(&MyScreen->ViewPort,&PlanetSprite[freeplanet],xpos,ypos);
  770.  
  771.    Mass[freeplanet] = 20;      /* default mass of the planet */
  772.    X[freeplanet] = xpos * SCALE_FACTOR;
  773.    Y[freeplanet] = ypos * SCALE_FACTOR;
  774.    Vx[freeplanet] = 0;
  775.    Vy[freeplanet] = 0;
  776.  
  777. }
  778. /* ======================================================================== */
  779. VOID DeletePlanet(Number)
  780. SHORT Number;
  781. {
  782.  MoveSprite(&MyScreen->ViewPort,&PlanetSprite[Number],70*Number,550);
  783.  
  784.  Mass[Number] = 0;      /* ZERO the mass of the planet */
  785.                            /* This Deactivates a planet to ensure */
  786.                            /* it is not used in the gravity evaluation */
  787.  PlanetNum--;
  788. }
  789. /* ======================================================================== */
  790. PlanetTouched(xpos,ypos)
  791. SHORT xpos,ypos;
  792. {
  793.  USHORT delx,dely,num;
  794.  int planetfound = 0;
  795.  
  796.  /* Software collision routine to detect a collision between the pointer */
  797.  /* and a given mass at xpos,ypos. */
  798.  
  799.  for (num = 1; num <= 6; num++ )
  800.    {
  801.      delx = absolute( PlanetSprite[num].x + 4 - xpos );
  802.      dely = absolute( PlanetSprite[num].y + 4 - ypos ); 
  803.  
  804.      if (delx < 5 && dely < 5) 
  805.        {
  806.          planetfound = num;
  807.          break;
  808.        }
  809.  
  810.    }
  811.  
  812.  return(planetfound);
  813.  
  814. }
  815.  
  816. /* ======================================================================== */
  817.  
  818. VOID SetMass(pnum,x,y,stateflag)
  819. LONG pnum,x,y,stateflag;
  820.  
  821. {
  822.  static struct IntuiText mesg;
  823.  static char NewMassString[7], OldMassString[7];
  824.  static int Xdrw,Ydrw;
  825.  static float PlanetMass;
  826.  int i;
  827.  
  828.  switch(stateflag)
  829.    {
  830.      case StartCoord:   mesg.FrontPen = 1;
  831.                         mesg.BackPen = 0;
  832.                         mesg.DrawMode = COMPLEMENT;
  833.                         mesg.LeftEdge = 0;
  834.                         mesg.TopEdge = 0;
  835.                         mesg.ITextFont = NULL;
  836.                         mesg.IText = NULL;
  837.                         mesg.NextText = NULL;
  838.                         Xdrw = x + 7;   /* the coordinates of the string */
  839.                         Ydrw = y;
  840.                         PlanetMass = Mass[pnum];
  841.                         /* init old string to the mass of that planet */
  842.                         sprintf(OldMassString,"%d",(int)PlanetMass);
  843.                         mesg.IText = (UBYTE *) OldMassString;
  844.                         PrintIText(NoBorder->RPort,&mesg,Xdrw,Ydrw);
  845.                         break;
  846.  
  847.      case NewCoord:     /* erase old string .. */
  848.                         mesg.IText = (UBYTE *) OldMassString;
  849.                         WaitTOF();
  850.                         PrintIText(NoBorder->RPort,&mesg,Xdrw,Ydrw);
  851.  
  852.                         /* calculate the new mass size from the */
  853.                         /* current mouse Y- coords. */
  854.  
  855.                         PlanetMass = (absolute(Ydrw - y) + 0.8)/0.6 ;
  856.                         /* convert the float into a float string */
  857.                         sprintf(NewMassString,"%d",(int)PlanetMass);
  858.                         
  859.                         /* print new string .. */
  860.                         mesg.IText = (UBYTE *) NewMassString;
  861.                         WaitTOF();
  862.                         PrintIText(NoBorder->RPort,&mesg,Xdrw,Ydrw);
  863.  
  864.                         /* Save to old string */
  865.                         i = 0;
  866.                         while ( ( OldMassString[i] = NewMassString[i] ) != '\0')
  867.                              i++;
  868.  
  869.                         break;
  870.  
  871.      case EndCoord:     /* erase old string .. */
  872.                         mesg.IText = (UBYTE *) OldMassString;
  873.                         PrintIText(NoBorder->RPort,&mesg,Xdrw,Ydrw);
  874.  
  875.                         /* store the new mass for that planet */
  876.                         Mass[pnum] = PlanetMass;
  877.                         break;
  878.  
  879.        } 
  880.  
  881. }
  882. /* ======================================================================== */
  883. VOID PlayBack()
  884. {
  885.  SHORT Number,sx,sy;
  886.  int CurrentFrame,i,del;
  887.  struct SimpleSprite TempSprite[7]; /* Temp Sprite posns */
  888.  
  889.  ClrScreen();
  890.   
  891.  /* save current sprite positions before the animation */
  892.  
  893.  for (i = 1 ; i < 7 ; i++ )
  894.      TempSprite[i] = PlanetSprite[i];
  895.  
  896.  /* REPLAY the ANIMATION! ... */
  897.  
  898.  for ( CurrentFrame = 0 ; CurrentFrame < frame ; CurrentFrame++ )
  899.    {
  900.      /* do the delay as requested by the user */
  901.      for( del = 0 ; del < DelayFactor ; del++);
  902.         
  903.  
  904.      Number = MoviePlanet[CurrentFrame];
  905.      sx = MovieScreenX[CurrentFrame];
  906.      sy = MovieScreenY[CurrentFrame];
  907.  
  908.      MoveSprite(&MyScreen->ViewPort,&PlanetSprite[Number],sx,sy);
  909.  
  910.      if (PLANETPATH)     /* Toggle the paths */
  911.        {
  912.         if (COLOURPATHS)
  913.           SetAPen(NoBorder->RPort,((Number % 4) ? Number : 1));
  914.         WritePixel(NoBorder->RPort,sx+6,sy+3);
  915.        }
  916.    }    
  917.  
  918.  /* Restore old current sprite positions before the animation */
  919.  
  920.  for (i = 1 ; i < 7 ; i++ )
  921.     {
  922.       sx = TempSprite[i].x;
  923.       sy = TempSprite[i].y;
  924.       MoveSprite(&MyScreen->ViewPort,&PlanetSprite[i],sx,sy);
  925.     }   
  926.  
  927. }
  928. /* ======================================================================== */
  929. VOID ResetValues()
  930. {
  931.  int p,sx,sy;
  932.   
  933.  /* Restore all planets to the states they were in BEFORE the last */
  934.  /* animation was computed. */
  935.  
  936.  ClrScreen();
  937.  
  938.   for (p=1 ; p<=6 ; p++ )
  939.     {
  940.      if (Mass[p])
  941.        { 
  942.         sx = X[p] = tempX[p] ;  
  943.         sy = Y[p] = tempY[p] ;  
  944.         MoveSprite(&MyScreen->ViewPort,&PlanetSprite[p],sx/SCALE_FACTOR,sy/SCALE_FACTOR);
  945.         Mass[p] = tempMass[p] ;    
  946.         Vx[p] = tempVx[p] ;   
  947.         Vy[p] = tempVy[p] ; 
  948.        }  
  949.     }
  950. }
  951. /* ======================================================================== */
  952. VOID TotalReset()
  953. {
  954.  int p;
  955.  
  956.  ClrScreen();
  957.  
  958.  for (p= 1 ; p <= 6; p++ )
  959.   {
  960.    Mass[p] = 0;
  961.    Vx[p] = 0;
  962.    Vy[p] = 0;
  963.    MoveSprite(&MyScreen->ViewPort,&PlanetSprite[p],p*50,600);
  964.   }
  965.  PlanetNum = 0;
  966. }
  967. /* ======================================================================== */
  968. char *GetFilename()
  969. {
  970.   int j,looping = TRUE;
  971.   struct IntuiMessage *mes;
  972.   ULONG class;
  973.   static char filename[30];
  974.  
  975.   while (looping)
  976.   {
  977.     if ( (mes = (struct IntuiMessage *) GetMsg(NoBorder->UserPort) ) == 0L)
  978.       {
  979.         Wait(1L<<NoBorder->UserPort->mp_SigBit);
  980.         continue;
  981.       }
  982.      class = mes->Class;        
  983.      ReplyMsg(mes);
  984.      if (class == REQCLEAR)
  985.        looping = FALSE;
  986.    }
  987.   j = 0;
  988.   strcpy(filename,StringGadSIBuff);
  989.   while (filename[j] != 0)
  990.     {
  991.       if (filename[j] == '.') 
  992.          break;
  993.        j++;
  994.     }
  995.   filename[j] = 0;
  996.  
  997.   if (strlen(filename) != 0)
  998.     strcat(filename,".GSim");
  999.  
  1000.   return(filename);
  1001. }
  1002. /* ======================================================================== */
  1003. VOID LoadFile()
  1004. {
  1005.  FILE *fopen(), *fp;
  1006.  int i;
  1007.  SHORT sx,sy;
  1008.  char *filename;
  1009.  
  1010.   /* Obtain the filename the user typed into the string gadget */
  1011.  filename = GetFilename();
  1012.  
  1013.  if ((fp = fopen(filename,"r")) != NULL)     /* prepare to read the data file */
  1014.    {
  1015.      /* if everything is OK... */
  1016.      ClrScreen();
  1017.      TotalReset();   /* clear everything */
  1018.       
  1019.      /* read in the X & y coordinates of the planets */ 
  1020.  
  1021.      for (i=1; i <= 6; i++)
  1022.           fscanf(fp,"%f%f",&X[i],&Y[i]);
  1023.  
  1024.      for (i=1; i <= 6; i++)
  1025.          fscanf(fp,"%f%f",&Vx[i],&Vy[i]);
  1026.  
  1027.      for (i=1; i <= 6; i++)
  1028.         {
  1029.           fscanf(fp,"%f",&Mass[i]);
  1030.           if (Mass[i]) PlanetNum++;
  1031.         }
  1032.      fclose(fp);
  1033.         
  1034.      /* Re-position the sprites on the screen */
  1035.         
  1036.      for (i=1; i<=6 ; i++)
  1037.        {
  1038.          sx = X[i]/SCALE_FACTOR;
  1039.          sy = Y[i]/SCALE_FACTOR;
  1040.          MoveSprite(&MyScreen->ViewPort,&PlanetSprite[i],sx,sy);
  1041.         }
  1042.    }
  1043.   else
  1044.     DisplayBeep(MyScreen);  /* there was an error do a display beep ! */
  1045. }
  1046. /* ======================================================================== */
  1047. VOID SaveFile()
  1048. {
  1049.  FILE *fopen(), *fp;
  1050.  char *filename;
  1051.  int i;
  1052.  
  1053.  filename =  GetFilename();
  1054.  
  1055.  /* Obtain the filename the user typed into the string gadget */
  1056.  /* prepare to read the data file */
  1057.  
  1058.  if ((fp = fopen(filename,"w")) != NULL )     
  1059.    {
  1060.      /* if everything is OK... */
  1061.  
  1062.      /* read in the X & y coordinates of the planets */ 
  1063.  
  1064.      for (i=1; i <= 6; i++)
  1065.          fprintf(fp,"%f\t%f\n",X[i],Y[i]);
  1066.  
  1067.      for (i=1; i <= 6; i++)
  1068.          fprintf(fp,"%f\t%f\n",Vx[i],Vy[i]);
  1069.  
  1070.      for (i=1; i <= 6; i++)
  1071.          fprintf(fp,"%f\n",Mass[i]);
  1072.         
  1073.      fclose(fp);
  1074.    }
  1075.   else
  1076.     DisplayBeep(MyScreen);  /* there was an error do a display beep ! */
  1077.  
  1078. }
  1079. /* ======================================================================== */
  1080. static VOID domenu(menu, item, subitem)
  1081. USHORT menu, item, subitem;
  1082. {
  1083.   PLACEPLANET = FALSE;
  1084.   REMOVEPLANET = FALSE;
  1085.   SETVELOCITY = FALSE;
  1086.   SETMASS = FALSE;
  1087.  
  1088.   switch(menu)
  1089.    {
  1090.      case PROJECT_MENU :
  1091.          {
  1092.           switch (item) 
  1093.             {
  1094.              case  NEW_ITEM:   TotalReset();
  1095.                                MakePlanet(320,256);
  1096.                                break;
  1097.  
  1098.              case  LOAD_ITEM:  if ((Request(&RequesterStructure2,NoBorder)) == 1)
  1099.                                  LoadFile();
  1100.                                else
  1101.                                  printf("CANNOT OPEN REQUESTER!!\n");
  1102.                                break;
  1103.  
  1104.              case  SAVE_ITEM:  if ((Request(&RequesterStructure2,NoBorder)) == 1)
  1105.                                  SaveFile();
  1106.                                else
  1107.                                  printf("CANNOT OPEN REQUESTER!!\n");
  1108.                                break;
  1109.  
  1110.              case  QUIT_ITEM:    CloseUpShop();
  1111.                                  printf("Thats all Folks!!!\n");
  1112.                                  printf("Have a nice day.\n");
  1113.                                  exit(0); 
  1114.                                  break;
  1115.             } 
  1116.  
  1117.          }break;
  1118.  
  1119.      case PLANETS_MENU : 
  1120.          {  
  1121.           switch(item)
  1122.             {
  1123.               case PLACEPLANET_ITEM:  PLACEPLANET = TRUE;
  1124.                                       break;
  1125.  
  1126.               case REMOVEPLANET_ITEM: REMOVEPLANET = TRUE;
  1127.                                       break;
  1128.  
  1129.               case SETVELOCITY_ITEM: SETVELOCITY = TRUE;
  1130.                                      SetAPen(NoBorder->RPort,PenColour);
  1131.                                      break;
  1132.  
  1133.               case SETMASS_ITEM:  SETMASS = TRUE;
  1134.                                   break;
  1135.  
  1136.               case PATHS_ITEM:  switch(subitem) {
  1137.                                   case 0: PLANETPATH = TRUE;
  1138.                                           break;
  1139.  
  1140.                                   case 1: PLANETPATH = FALSE;
  1141.                                           break;
  1142.  
  1143.                                   case 2: COLOURPATHS = TRUE;
  1144.                                           break;
  1145.  
  1146.                                   case 3: COLOURPATHS = FALSE;
  1147.                                           SetAPen(NoBorder->RPort,PenColour);
  1148.                                           break;
  1149.                                 }
  1150.                                 break;
  1151.  
  1152.             }
  1153.          }break;
  1154.  
  1155.      case ANIMATION_MENU : 
  1156.          {  
  1157.           switch(item)
  1158.             {
  1159.               case STARTANIM_ITEM:  
  1160.                                     ClrScreen();
  1161.                                     COMPUTEANIM = TRUE;
  1162.                                     MovePlanets();
  1163.                                     break;
  1164.  
  1165.               case STOPANIM_ITEM: 
  1166.                                   COMPUTEANIM = FALSE;
  1167.                                   break;
  1168.  
  1169.               case RESTARTANIM_ITEM: 
  1170.                                      /* RESET VALUES */
  1171.                                      ResetValues();
  1172.                                     break;
  1173.             }
  1174.          }break;
  1175.  
  1176.      case RECORDER_MENU : 
  1177.          {  
  1178.           switch(item)
  1179.             {
  1180.               case RECORDER_ON_ITEM:  RECORD = TRUE;
  1181.                                       DisplayStats(frame);
  1182.                                       frame = 0;
  1183.                                       break;
  1184.  
  1185.               case RECORDER_OFF_ITEM: RECORD = FALSE;
  1186.                                       RestoreTitle();                                     
  1187.                                       break;
  1188.  
  1189.               case PLAYBACK_ITEM:    PlayBack();
  1190.                                      break;
  1191.  
  1192.               case PLAYBACKSPEED_ITEM:  switch (subitem) 
  1193.                                          {
  1194.                                            case 0:  DelayFactor = 0;
  1195.                                                     break;
  1196.  
  1197.                                            case 1:  DelayFactor = 100;
  1198.                                                     break;
  1199.  
  1200.                                            case 2:  DelayFactor = 300;
  1201.                                                     break;
  1202.                                          }
  1203.             }
  1204.          }
  1205.    } /* end switch */
  1206.   
  1207. }
  1208. /* ============================ MAIN PROGRAM =========================== */
  1209. main ()
  1210. {
  1211.  BOOL MouseMoved = FALSE,
  1212.       PenDown = FALSE,
  1213.       HitPlanet= FALSE;
  1214.  
  1215.  
  1216.  USHORT class;          /*Message class from Intuition */
  1217.  ULONG code;            /*Menu code from Intuition */
  1218.  SHORT x,y,
  1219.        PlanetNumber;
  1220.  
  1221.  
  1222.  VOID OpenAll(),SetUpFrontEnd(),CloseUpShop(),
  1223.       domenu(),
  1224.       MakePlanet(),DeletePlanet(),MovePlanets(),
  1225.       SetVelocityVector(),
  1226.       SetMass();
  1227.  
  1228.  
  1229.  
  1230.  
  1231.  OpenAll();     /*  Open GfxBase & Intuition   */
  1232.  SetUpFrontEnd();  /* Initialize Screens, Windows, Menus, SPRITES etc.  */
  1233.  MakePlanet(100,256);
  1234.  MakePlanet(400,256);
  1235.  
  1236.  
  1237.  
  1238.                         /*    MAIN PROGRAM MAJOR LOOP!    */ 
  1239.  
  1240.  
  1241.  
  1242.  for (;;)   /* INFINITE LOOP!! */
  1243.  {
  1244.   Wait(1L << NoBorder->UserPort->mp_SigBit);  /* Wait until a signal occurs */
  1245.   MouseMoved= FALSE;
  1246.   
  1247.   while( message=(struct IntuiMessage *) GetMsg(NoBorder->UserPort) )
  1248.     {
  1249.       /* If a message was recieved .... */
  1250.  
  1251.       class = message->Class;       /* Store the message class! */
  1252.       code = message->Code;         /* Store the code */
  1253.       x = NoBorder->MouseX;         /* Store away the mouse positions */
  1254.       y = NoBorder->MouseY;
  1255.  
  1256.       ReplyMsg(message);      /* And all importantly, TELL INTUITION 
  1257.                                 THAT YOU RECEIVED IT!!  */
  1258.                               /* So that the message port can be cleared! */
  1259.   
  1260.  
  1261.      /* Here is the 'case' statement which SORTS OUT all incoming MESSAGES */
  1262.  
  1263.            
  1264.      switch (class)
  1265.      {            
  1266.  
  1267.               /* HANDLE ALL EVENTS THAT INTUITION PASSES TO ME */
  1268.  
  1269.       case  MOUSEMOVE :  MouseMoved = TRUE;
  1270.                          break; 
  1271.                              
  1272.       case  MENUPICK :   if (MENUNUM(code) != MENUNULL)
  1273.                            domenu(MENUNUM(code),ITEMNUM(code),SUBNUM(code));
  1274.                          break;
  1275.                          
  1276.                          /* If Left Mouse Button Pressed then it could
  1277.                             be meant for either:
  1278.                                 
  1279.                                 1:  1st position (x,y) in placing planet
  1280.                                 2:  coord (x,y) of a planet to be deleted
  1281.                                
  1282.                                 Thus the Action Mode Flags sort this
  1283.                                 out appropriately
  1284.                              */     
  1285.  
  1286.       case  MOUSEBUTTONS: if (code == SELECTDOWN) 
  1287.                            {  
  1288.                              PenDown = TRUE;
  1289.                              if (PLACEPLANET)
  1290.                               {
  1291.                                 if (PlanetNum < 6)
  1292.                                       MakePlanet(x,y);
  1293.                                 else
  1294.                                   DisplayBeep(MyScreen);
  1295.                               }
  1296.                              else
  1297.                                if (REMOVEPLANET)
  1298.                                  {
  1299.                                   /* Now check for a collision with */
  1300.                                   /* the intuition pointer... */
  1301.                                   /* if there was a collision ... */
  1302.  
  1303.                                   if (PlanetNum > 1) 
  1304.                                     {
  1305.                                      if ( (PlanetNumber = PlanetTouched(x,y)) != 0)
  1306.                                            DeletePlanet(PlanetNumber);
  1307.                                     }
  1308.                                   else DisplayBeep(MyScreen);
  1309.                                  }
  1310.                              else
  1311.                                if (SETVELOCITY)
  1312.                                  {
  1313.                                   if ( (PlanetNumber = PlanetTouched(x,y)) != 0)
  1314.                                     {
  1315.                                      HitPlanet = TRUE;
  1316.                                      SetDrMd(NoBorder->RPort,COMPLEMENT);
  1317.                                      SetVelocityVector(PlanetNumber,x,y,StartCoord);
  1318.                                     }
  1319.                                  }
  1320.                              else
  1321.                                if (SETMASS)
  1322.                                  {
  1323.                                   if ( (PlanetNumber = PlanetTouched(x,y)) != 0)
  1324.                                     {
  1325.                                      HitPlanet = TRUE;
  1326.                                      SetMass(PlanetNumber,x,y,StartCoord); 
  1327.                                     }
  1328.                                  }
  1329.  
  1330.                           } /* end 'if code == selectdown' */
  1331.  
  1332.                         else if (code == SELECTUP)
  1333.                                {
  1334.                                  PenDown= FALSE;
  1335.                                  if ((SETVELOCITY) && (HitPlanet))
  1336.                                    {
  1337.                                      SetVelocityVector(PlanetNumber,x,y,EndCoord);
  1338.                                      HitPlanet = FALSE;
  1339.                                    }
  1340.                                 else
  1341.                                  if ((SETMASS) && (HitPlanet))
  1342.                                    {
  1343.                                      SetMass(PlanetNumber,x,y,EndCoord);
  1344.                                      HitPlanet = FALSE;
  1345.                                    }
  1346.                                }
  1347.                         break;
  1348.  
  1349.        }/* end Switch */
  1350.  
  1351.     } /*end While Loop */
  1352.  
  1353.     if (MouseMoved)
  1354.       {
  1355.        if (PenDown)     /* if LEFT mouse button DOWN */
  1356.          {
  1357.            if (HitPlanet)
  1358.              {
  1359.               if (SETVELOCITY)     /* and in SET VELOCITY MODE ..*/        
  1360.                 SetVelocityVector(PlanetNumber,x,y,NewCoord);
  1361.               else
  1362.                 if (SETMASS)
  1363.                   SetMass(PlanetNumber,x,y,NewCoord);
  1364.              }
  1365.          }
  1366.       }
  1367.         
  1368.  
  1369.  }/* end infinite FOR LOOP */
  1370.  
  1371. } /* THATS ALL FOLKS! */
  1372.  
  1373.  
  1374.    
  1375.  
  1376.   
  1377.